package com.chengliang.bbs.controller;

import com.chengliang.bbs.entry.*;
import com.chengliang.bbs.service.*;
import com.chengliang.bbs.type.ColumnType;
import com.chengliang.bbs.type.ExperienceGrade;
import com.chengliang.bbs.type.UserIdentityType;
import com.chengliang.bbs.util.*;
import com.github.pagehelper.Page;
import com.wf.captcha.utils.CaptchaUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Collection;
import java.util.UUID;

/**
 * @author chengliang
 */
@Controller
@Slf4j
@RequestMapping("/user")
public class UserController {

    @Value("${project.url}")
    private String projectUrl;

    private final UserService userService;

    private final EmailUtil emailUtil;

    private final QQUtils qqUtils;

    private final FileUtils fileUtils;

    private final UserAuthsService authsService;

    private final AuthenticationManager authenticationManager;

    private final PasswordEncoder passwordEncoder;

    private final JieServsice jieServsice;

    private final ReplyService replyService;

    private final MessageService messageService;


    public UserController(UserService userService, EmailUtil emailUtil, QQUtils qqUtils, UserAuthsService authsService, AuthenticationManager authenticationManager, FileUtils fileUtils, PasswordEncoder passwordEncoder, JieServsice jieServsice, ReplyService replyService, MessageService messageService) {
        this.userService = userService;
        this.emailUtil = emailUtil;
        this.qqUtils = qqUtils;
        this.authsService = authsService;
        this.authenticationManager = authenticationManager;
        this.fileUtils = fileUtils;
        this.passwordEncoder = passwordEncoder;
        this.jieServsice = jieServsice;
        this.replyService = replyService;
        this.messageService = messageService;
    }

    /**
     * 我的帖子
     * @return
     */
    @GetMapping("/jie")
    public String jie(Model model){
        model.addAttribute("option","jie");
        return "user/jie";
    }

    /**
     * 查看消息
     * @param model
     * @return
     */
    @GetMapping("/message")
    public String message(Model model){
        model.addAttribute("option","message");
        //将该用户消息设置为已读
        messageService.read(UserUtils.currentUser().getUser().getUserId());
        model.addAttribute("messageList",messageService.getMessageListBy(UserUtils.currentUser().getUser().getUserId()));
        return "user/message";
    }

    /**
     * 我的主页
     * @param nickName
     * @param model
     * @return
     */
    @GetMapping("/name/{nickName}")
    public String name(@PathVariable String nickName,Model model){
        boolean existsUserNickName = userService.isExistsUserNickName(nickName);
        if(!existsUserNickName){
            model.addAttribute("columnTypes", ColumnType.values());
            return "other/404";
        }
        model.addAttribute("replyList",replyService.getReplyListByUserId(UserUtils.currentUser().getUser().getUserId(),1,10));
        model.addAttribute("jieList",jieServsice.getJieListByUserId(UserUtils.currentUser().getUser().getUserId(),1,10));
        model.addAttribute("user",userService.getUserByNickName(nickName));
        return "user/home";
    }

    /**
     * 用户主页
     * @param model
     * @return
     */
    @GetMapping("/home")
    public String  home(Model model){
        model.addAttribute("replyList",replyService.getReplyListByUserId(UserUtils.currentUser().getUser().getUserId(),1,10));
        model.addAttribute("jieList",jieServsice.getJieListByUserId(UserUtils.currentUser().getUser().getUserId(),1,10));
        model.addAttribute("user",userService.getUserByNickName(UserUtils.currentUser().getUser().getUserNickName()));
        log.debug("我的主页 昵称{} ,查询结果{}",UserUtils.currentUser().getUser().getUserNickName(),userService.getUserByNickName(UserUtils.currentUser().getUser().getUserNickName()));
        return "user/home";
    }

    /**
     * 我的发帖
     * @return
     */
    @PostMapping("/myjie")
    @ResponseBody
    public JSONResult myJie(@RequestParam(defaultValue = "1") Integer page,@RequestParam(defaultValue = "10") Integer limit){
        Page<Jie> jieList = jieServsice.getJieListByUserId(UserUtils.currentUser().getUser().getUserId(), page, limit);
        return JSONResult.success(jieList)
                .append("count",jieList.getTotal());
    }

    /**
     * 用户中心
     * @return
     */
    @GetMapping("/index")
    public String index(Model model){
        model.addAttribute("isIfverified",UserUtils.currentUser().getUserIfverified());
        User user = userService.getUserByUserId(UserUtils.currentUser().getUser().getUserId());
        model.addAttribute("user",user);
        model.addAttribute("experienceRecordName",ExperienceGrade.getDescriptionByExperience(user.getTotalExperience()));
        model.addAttribute("option","index");
        return "user/index";
    }

    /**
     * 解除绑定
     * @param identityType
     * @return
     */
    @PostMapping("/unbind")
    @ResponseBody
    public JSONResult unbind(UserIdentityType identityType){
        Integer userId = UserUtils.currentUser().getUserId();
        boolean isok = userService.unbind(userId,identityType);
        if(!isok){
            return JSONResult.error("解除绑定失败,请至少保留一种登录方式");
        }
        return JSONResult.success();
    }

    /**
     * 修改密码
     * @param nowPass
     * @param pass
     * @param rePass
     * @return
     */
    @PostMapping("/repass")
    @ResponseBody
    public JSONResult repass(String nowPass,String pass,String rePass){
        if(StringUtil.isEmpty(nowPass) || StringUtil.isEmpty(pass) || StringUtil.isEmpty(rePass)){
            return JSONResult.error();
        }
        if(!pass.equals(rePass)){
            return JSONResult.error("新密码与确认密码不一致");
        }
        UserAuths userAuths = UserUtils.currentUser();
        //原密码
        if(!passwordEncoder.matches(nowPass , userAuths.getUserCredential())){
            return JSONResult.error("原密码输入错误");
        }
        //原密码与新密码一致
        if(passwordEncoder.matches(pass , userAuths.getUserCredential())){
            return JSONResult.error("原密码与新密码一致");
        }
        if(!authsService.updatePassowrdByUserId(userAuths.getUserId(), pass)){
            return JSONResult.error("密码修改失败，请重试");
        }
        return JSONResult.success("密码修改成功，请使用新密码重新登录。").append("action","/user/logout");
    }


    /**
     * 头像上传
     * @param file
     * @param request
     * @return
     */
    @PostMapping("/upload")
    @ResponseBody
    public JSONResult upload(@RequestParam("file") MultipartFile file,HttpServletRequest request){
        String avatarUrl = fileUtils.saveFile("images", file);
        if(StringUtil.isEmpty(avatarUrl)){
            return JSONResult.error("头像上传失败，请重试");
        }
        //同步session 头像信息
        UserUtils.updateAuthsCurrUser(new User().setUserAvatar(avatarUrl));
        return JSONResult.success().append("url",avatarUrl);
    }

    /**
     * 激活
     * @param session
     * @return
     */
    @PostMapping("/activate")
    @ResponseBody
    public JSONResult activatePost(HttpSession session){
        //当前用户
        User user = UserUtils.currentUser().getUser();
        //邮箱是否存在
        if(StringUtil.isEmpty(user.getUserEmail())){
            return JSONResult.error("该邮箱未注册");
        }
        //邮箱是否授权过
        if(UserUtils.currentUser().getUserIfverified() == 0){
            return JSONResult.error("该邮箱已认证");
        }
        //发送邮件
        String token = UUID.randomUUID().toString();
        session.setAttribute(token,user.getUserEmail());
        //拼接邮箱内容
        StringBuffer content=new StringBuffer()
                .append("你好 ： ")
                .append(user.getUserNickName())
                .append(",点击链接验证 邮箱 :")
                .append(projectUrl)
                .append("/user/activate/?t=")
                .append(System.currentTimeMillis())
                .append("&token=").append(token)
                .append("<br><br>如果该邮件不是由你本人操作，请勿进行验证！否则你的邮箱将会被他人绑定。");
        //发送邮件
        return JSONResult.is(emailUtil.sendHtmlMail(user.getUserEmail(), "chengliangyun.com 邮箱验证", content.toString()),"邮件发送");
    }

    /**
     * 激活页面
     * @param token
     * @param session
     * @param model
     * @return
     */
    @GetMapping("/activate")
    public String activateGet(String token,HttpSession session,Model model){
        if(StringUtil.isEmpty(token)){
            return "user/activate";
        }
        //认证邮箱
        Object email = session.getAttribute(token);
        if(email == null){
            model.addAttribute("information","该链接已失效,请重新获取验证链接");
            return "other/tips";
        }
        //修改认证状态
        boolean b = authsService.updateIfverifiedByIdentifier(email.toString(), 0);
        if(!b){
            model.addAttribute("information","邮箱认证失败,请重试。");
            return "other/tips";
        }
        //认证成功 修改当前用户的认证状态
        session.removeAttribute(token);
        UserUtils.updateCurrAuthsIfverified(0);
        return "user/activate";
    }


    /**
     * 修改用户信息
     * @param user
     * @return
     */
    @PostMapping("/set")
    @ResponseBody
    public JSONResult set(User user){
        if(user == null){
            return JSONResult.error("用户信息不可为空");
        }
        //当前用户
        UserAuths userAuths = UserUtils.currentUser();
        //邮箱发生变化
        if(!userAuths.getUser().getUserEmail().equals(user.getUserEmail())){
            //修改账号认证状态
            authsService.updateIfverifiedByIdentifier(userAuths.getUser().getUserEmail(),1);
        }
        return JSONResult.is(userService.updateUserInfoByUserId(user.setUserId(userAuths.getUserId())),"用户信息修改");
    }

    /**
     * 用户设置页面
     * @return
     */
    @GetMapping("/set")
    public String setPage(Model model){
        UserAuths userAuths = UserUtils.currentUser();
        log.debug("设置页面{}",userAuths);
        model.addAttribute("user",userService.getUserByUserId(userAuths.getUser().getUserId()));
        model.addAttribute("option","set");
        model.addAttribute("qqIsBind",userService.isQQBind(userAuths.getUserId()));
        return "user/set";
    }

    /**
     * qq登录回调地址
     * @param code qq发送过来的code
     * @param state 回传state值
     * @return
     */
    @GetMapping("/login/qq/callback")
    public String qqLoginCall(String code,String state,HttpSession session){
        //效验state值
        if(!qqUtils.checkState(state,session)){
            return "redirect:/user/login";
        }
        //获取token信息
        String token = qqUtils.getTokenByCode(code);
        //获取openId
        String openId = qqUtils.getOpenIdByToken(token);
        //查看该qq是否登陆过
        UserAuths userAuths = authsService.getUserAuths(openId);
        //该用户未注册过
        if(userAuths==null){
            //调用qq接口获取用户信息
            userAuths = qqUtils.getUserAuths(token, openId);
            log.debug("QQ接口获取的对象信息{}",userAuths);
            //已登录则是绑定账号
            UserAuths currentUser = UserUtils.currentUser();
            if(currentUser != null){
                userAuths.getUser().setUserId(currentUser.getUserId());
            }
            //保存到数据库中
            userService.register(userAuths.getUser()
                    , userAuths.setUserIdentityType(UserIdentityType.qq).setUserAuthorities("user").setUserIfverified(0));
            log.debug("保存到数据库中以后用户信息{}",userAuths);
            //绑定账号
            if(currentUser != null){
                return "redirect:/user/set#bind";
            }
        }
        //认证通过
        Collection<? extends GrantedAuthority> authorities = userAuths.getAuthorities();
        log.info("qq登录用户信息{}",userAuths);
        SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(userAuths, userAuths.getPassword(),authorities));
        return "redirect:/";
    }

    /**
     * qq登录
     * @return
     */
    @GetMapping("/login/qq/")
    public String qqLogin(HttpSession session){
        return qqUtils.getQQLoginUrl(session);
    }

    /**
     * 修改密码
     * @param pass 新密码
     * @param repass 确认密码
     * @param vercode 验证码
     * @param request
     * @return
     */
    @PostMapping("/forget/repass")
    @ResponseBody
    public JSONResult forgetRePass(String pass,String repass,String vercode,HttpServletRequest request){
        if(StringUtil.isEmpty(pass) || StringUtil.isEmpty(repass) || StringUtil.isEmpty(vercode)){
            return JSONResult.error("请填写必要信息重置密码");
        }
        //比较验证码
        if (!CaptchaUtil.ver(vercode, request)) {
            //清除验证码
            CaptchaUtil.clear(request);
            return JSONResult.error("验证码输入错误");
        }
        //对比密码
        if(!pass.equals(repass)){
            return JSONResult.error("新密码与确认密码不一致");
        }
        //修改密码
        String nickName = (String) request.getSession().getAttribute("nickName");
        boolean b = userService.updatePasswordByNickName(nickName, pass);
        if(!b){
            return JSONResult.error("密码修改失败,请重试");
        }
        request.getSession().removeAttribute("nickName");
        return JSONResult.success("密码修改成功,请进行登录").append("action","/user/login");
    }

    /**
     * 重置密码链接处理
     * @param code
     * @param model
     * @param session
     * @return
     */
    @GetMapping("/forget/repass")
    public String forgetRePassPage(String code, Model model,HttpSession session){
        String email=null;
        if(StringUtil.isEmpty(code) || StringUtil.isEmpty(email=(String)session.getAttribute(code))){
            model.addAttribute("error","重置链接已失效或错误");
            log.error("code{},重置链接已失效或错误{}",code,email);
            return "user/forget";
        }
        //获取昵称
        String nickName = userService.getNickNameByLoginName(email);
        session.setAttribute("nickName",nickName);
        model.addAttribute("type","repass");
        log.info("找回密码用户昵称{}",nickName);
        return "user/forget";
    }

    /**
     * 忘记密码：邮箱发送重置链接
     * @param email 邮箱地址
     * @param vercode 验证码
     * @param request
     * @return
     */
    @PostMapping("/forget/")
    @ResponseBody
    public JSONResult forget(String email,String vercode,HttpServletRequest request){
        //信息不能为空
        if(StringUtil.isEmpty(email) || StringUtil.isEmpty(vercode)){
            return JSONResult.error("密码或验证码不能为空");
        }
        //验证码的校验
        if (!CaptchaUtil.ver(vercode, request)) {
            CaptchaUtil.clear(request);
            return JSONResult.error("验证码输入不正确");
        }
        //邮箱是否存在
        if(!userService.isExistsUserLoginName(email)){
            return JSONResult.error("该邮箱不存在,请检查邮箱地址");
        }
        //生成code
        String code = UUID.randomUUID().toString();
        request.getSession().setAttribute(code,email);
        //拼接邮箱内容
        StringBuffer content=new StringBuffer()
                .append("请在30分钟内完成重置密码<br>点击该链接重置密码 :")
                .append(projectUrl)
                .append("/user/forget/repass?t=")
                .append(System.currentTimeMillis())
                .append("&code=").append(code);
        log.info("uuid{},邮件内容:{}",code,content);
        //发送邮件
        boolean b = emailUtil.sendHtmlMail(email, "chengliangyun 找回密码", content.toString());
        if(!b){
            return JSONResult.error("邮件发送失败,请重试");
        }
        return JSONResult.success("找回密码链接已发送到邮箱,请使用当前浏览器打开链接。").append("action","/user/login");
    }
    /**
     * 忘记密码页面
     * @return
     */
    @GetMapping("/forget/")
    public String forgetPage(Model model){
        model.addAttribute("type","forget");
        return "user/forget";
    }

    /**
     * 验证码
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping("/images/captcha.png")
    public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 设置宽、高、位数
        CaptchaUtil.outPng(120, 40, 4, request, response);
    }

    /**
     * 用户注册
     * @Author: chengliang
     * @Date: 2019-07-24
     * @Description:
     */
    @PostMapping("/reg")
    @ResponseBody
    public Object reg(User user, UserAuths userAuths, String repass, String vercode, HttpServletRequest httpServletRequest) throws InterruptedException {
        log.info("进行注册{}",user);
        //比较验证码
        if (!CaptchaUtil.ver(vercode, httpServletRequest)) {
            //清除验证码
            CaptchaUtil.clear(httpServletRequest);
            return JSONResult.error("验证码输入错误");
        }
        //验证用户信息
        if (StringUtil.isEmpty(user)|| StringUtil.isEmpty(userAuths)){
            return JSONResult.error("用户信息不可为空");
        }
        //昵称不可为null
        if(StringUtil.isEmpty(user.getUserNickName())){
            return JSONResult.error("昵称不可为空");
        }
        //不能为null
        if(StringUtil.isEmpty(userAuths.getUserIdentifier())){
            return JSONResult.error("请填写邮箱或手机号");
        }
        //比较重复密码
        if(userAuths.getUserCredential()!=null && !userAuths.getUserCredential().equals(repass)){
            return JSONResult.error("密码与重复密码输入不一致");
        }
        //验证是否存在
        if(StringUtil.isNotEmpty(userAuths.getUserIdentifier()) && userService.isExistsUserLoginName(userAuths.getUserIdentifier())){
            return JSONResult.error("该账号已注册");
        }
        //验证昵称是否存在
        if(userService.isExistsUserNickName(user.getUserNickName())){
            return JSONResult.error("该昵称已被使用");
        }
        //注册信息
        return JSONResult.is(userService.register(user,userAuths.setUserIfverified(1)),"注册").append("action","login");
    }

    /**
     * @return 注册页面
     */
    @GetMapping("/reg")
    public String regPage(){
        return "user/reg";
    }

    /**
     * @return 登录页面
     */
    @GetMapping("/login")
    public String login(){
        return "user/login";
    }


}
